home *** CD-ROM | disk | FTP | other *** search
/ 8bitfiles.net/archives / archives.tar / archives / compuserve-file-archive / 07 CP_M / CLK128.LBR / CLOCK.MZC / CLOCK.MAC
Encoding:
Text File  |  2019-04-13  |  16.1 KB  |  594 lines

  1. ;
  2. ; CLOCK.MAC -- Version 1.1 -- for Commodore C-128  CP/M Plus
  3. ;
  4. ; A utility to read "The Right Time" clock-calendar and set the
  5. ; system time and date under CP/M Plus on the Commodore 128.
  6. ;
  7. ; USAGE:
  8. ;
  9. ;    CLOCK
  10. ;
  11. ; No parameters are needed.
  12. ;
  13. ; There is one small bug.  When you call CLOCK from the CP/M command line,
  14. ; if the system time was previously set to a time later than the real time
  15. ; that the clock provides, the date will be advanced a day by the warm
  16. ; boot.  The apparent reason for this is that when the BDOS or CCP checks
  17. ; the time and finds it is earlier than the last time it checked, it
  18. ; assumes it's a new day and that the date should be incremented.  I don't
  19. ; know a way around this, but there may be a flag somewhere that I haven't
  20. ; found yet.  This situation should be a rare occurrence for most people.
  21. ; In any case running CLOCK a second time will set the date correctly.
  22. ;
  23. ; Much of this code is not original.  For the clock reading routines I
  24. ; relied heavily on the C-128 native mode driver written and copyrighted
  25. ; by Stephen Ardelt of Ardelt Engineering, manufacturers of The Right Time
  26. ; clock-calendar.  The most important changes were translating 6502 code
  27. ; to Z80 code and using Z80 in and out instructions to access the I/O chips,
  28. ; which are not visible in banks 1 or 0, the banks in which CP/M operates.
  29. ;
  30. ; Most of the subroutine to put the date in DRI format was taken from
  31. ; UNDATE.ASM, a procedure written by S. Kluger of the El Paso RCP/M.  It
  32. ; is in the public domain.  The original routine was written to read the
  33. ; time and date as ASCII strings, so it was modified to accept binary
  34. ; input.
  35. ;
  36. ; The Right Time is a trademark of Ardelt Engineering Company for their
  37. ; battery-backed clock-calendar for the Commodore 64 and 128.  The clock
  38. ; plugs into the User Port and, if you use a 1670 modem, it will plug into
  39. ; the back of the clock.  The RTC does not interfere with any CP/M functions,
  40. ; including Drive M: (the RAM disk).  You can get more information from
  41. ;    Ardelt Engineering Company
  42. ;    8175 East 39th Avenue
  43. ;    Denver, CO  80207
  44. ;    (800) 237-2943 for orders
  45. ;    (303) 355-1763 for technical information
  46. ;
  47. ; HISTORY:
  48. ;
  49. ; Version 1.0 -- December 5, 1987
  50. ;    Gene Pizzetta
  51. ;    481 Revere Street
  52. ;    Revere, MA  02151
  53. ;    Voice:  (617) 284-0891
  54. ;    CompuServe:  72060,505
  55. ;    GEnie:  E.Pizzetta
  56. ;    Q-Link:  GeneP
  57. ;
  58. ; Version 1.1 -- December 7, 1987 -- Added date and time display to console.
  59. ;    Gene Pizzetta
  60. ;
  61. ; This program was developed using SLRMAC from SLR Systems, just possibly
  62. ; the world's best assembler.  This source file can be assembled by MAC and
  63. ; HEXCOM (much more slowly, of course) by changing the filetype from .MAC
  64. ; to .ASM.  MAC will also require that you have Z80.LIB on the default drive.
  65. ;
  66. ; Note also that MAC will generate a meaningless error when it finds a line
  67. ; with an exclamation point in a comment.  Ignore the error; the generated
  68. ; code will be fine.
  69. ;
  70. ;
  71. ; System addresses
  72. ;
  73. WBoot    equ    0000h        ; warm boot
  74. Bdos    equ    0005h        ; BDOS entry
  75. PrtStr    equ    09h        ; BDOS print string
  76. SetSCB    equ    031h        ; BDOS set/get system control block
  77. BEL    equ    07h
  78. LF    equ    0Ah
  79. CR    equ    0Dh
  80. ;
  81. ; CIA #1
  82. ;
  83. Cia1PA    equ    0DC00h        ; port A
  84. Cia1PB    equ    0DC01h        ; port B
  85. Cia1DA    equ    0DC02h        ; data direction register A
  86. Cia1DB    equ    0DC03h        ; data direction register B
  87. Cia1Ten    equ    0DC08h        ; tenths of a second
  88. Cia1Sec    equ    0DC09h        ; seconds
  89. Cia1Min    equ    0DC0Ah        ; minutes
  90. Cia1Hrs    equ    0DC0Bh        ; hours
  91. Cia1IC    equ    0DC0Dh        ; interrupt control register
  92. Cia1CA    equ    0DC0Eh        ; control register A
  93. Cia1CB    equ    0DC0Fh        ; control register B
  94. ;
  95. ; CIA #2
  96. ;
  97. Cia2PA    equ    0DD00h        ; port A
  98. Cia2PB    equ    0DD01h        ; port B
  99. Cia2DA    equ    0DD02h        ; data direction register A
  100. Cia2DB    equ    0DD03h        ; data direction register B
  101. Cia2Ten    equ    0DD08h        ; tenths of a second
  102. Cia2Sec    equ    0DD09h        ; seconds
  103. Cia2Min    equ    0DD0Ah        ; minutes
  104. Cia2Hrs    equ    0DD0Bh        ; hours
  105. Cia2IC    equ    0DD0Dh        ; interrupt control register
  106. Cia2CA    equ    0DD0Eh        ; control register A
  107. Cia2CB    equ    0DD0Fh        ; control register B
  108. ;
  109.     MACLIB    Z80
  110. ;
  111.     org    100h
  112. ;
  113.     jmp    START
  114. ;
  115. ; data storage and tables
  116. ;
  117. CiaSav:    db    0,0,0,0        ; original CIA #2 port configuration
  118. LoNib:    db    0        ; low nibble data during RTC read
  119. Secs:    db    0        ; seconds read from RTC
  120. Mins:    db    0        ; minutes read from RTC
  121. Hours:    db    0        ; hours read from RTC
  122. Month:    db    0        ; month read from RTC
  123. BMonth    db    0        ; binary month
  124. Date:    db    0        ; date read from RTC
  125. BDate:    db    0        ; binary date
  126. Year:    db    0        ; year read from RTC
  127. BYear    db    0        ; binary year
  128. Jan:    db    31        ; January
  129. Feb:    db    28,31,30,31,30    ; February to June
  130.     db    31,31,30,31,30    ; July to November
  131. Days:    dw    0        ; total days sum for UNDATE
  132. ScbPB:    db    58h,0FEh    ; SCB parameter block for
  133. ScbVal:    dw    0        ; ..BDOS Function 49
  134. ;
  135. ; messages
  136. ;
  137. MsgSOn:    db    'C-128  CLOCK    Version 1.1',CR,LF,LF,'$'
  138. MsgNCk:    db    BEL,' Clock not installed.',CR,LF,'$'
  139. MsgBat:    db    BEL,' Clock not set or battery dead.',CR,LF,'$'
  140. MsgDRI:    db    BEL,' CP/M date out of range.',CR,LF,'$'
  141. MsgDat:    db    '     Date:  '
  142. AMonth:    db    0,0,'/'
  143. ADay:    db    0,0,'/'
  144. AYear:    db    0,0,CR,LF,'$'
  145. MsgTim:    db    '     Time:  '
  146. AHours:    db    0,0,':'
  147. AMins:    db    0,0,':'
  148. ASecs:    db    0,0,CR,LF,'$'
  149. ;
  150. START:    lxi    d,MsgSOn    ; print sign-on
  151.     mvi    c,PrtStr
  152.     call    Bdos
  153. ;
  154.     di            ; disable interrupts
  155.     mvi    a,07Fh        ; disable NMI's
  156.     lxi    b,Cia2IC
  157.     outp    a
  158.     lxi    b,Cia2CA    ; set bit 7 of CIA#2 control register A
  159.     inp    a        ; to 60hz
  160.     ani    07Fh
  161.     outp    a
  162.     lxi    b,Cia2CB    ; set bit 7 of CIA#2 control register B
  163.     inp    a        ; to clock
  164.     ani    07Fh
  165.     outp    a
  166.     lxi    b,Cia1CA    ; set bit 7 of CIA#1 control register A
  167.     inp    a        ; to 60hz
  168.     ani    07Fh
  169.     outp    a
  170.     lxi    b,Cia1CB    ; set bit 7 of CIA#1 control register B
  171.     inp    a        ; to clock
  172.     ani    07Fh
  173.     outp    a
  174.     lxi    b,Cia2PA    ; save CIA#2 port setup (4 bytes)
  175.     lxi    d,CiaSav
  176.     inp    a
  177.     stax    d        ; (1)
  178.     lxi    b,Cia2PB
  179.     inx    d
  180.     inp    a
  181.     stax    d        ; (2)
  182.     lxi    b,Cia2DA
  183.     inx    d
  184.     inp    a
  185.     stax    d        ; (3)
  186.     lxi    b,Cia2DB
  187.     inx    d
  188.     inp    a
  189.     stax    d        ; (4)
  190. ;
  191. ; Now we're ready to open the channels to The Right Time clock
  192. ;
  193.     mvi    a,03Fh        ; set CIA#2 DDR A to default
  194.     lxi    b,Cia2DA
  195.     outp    a
  196.     mvi    a,0FFh        ; set CIA#2 DDR B to outputs
  197.     lxi    b,Cia2DB
  198.     outp    a
  199.     lxi    b,Cia2PA    ; make sure PA2 is high (bit 3 = 4)
  200.     inp    a
  201.     ori    04h
  202.     outp    a
  203.     lxi    b,Cia2PB    ; set PB5 high, all others low
  204.     mvi    a,20h
  205.     outp    a
  206.     lxi    b,Cia2PA    ; set PA2 low (chip select)
  207.     inp    a
  208.     ani    0FBh
  209.     outp    a
  210.     lxi    b,Cia2PB    ; set PB5 low first time (counter goes to 1)
  211.     mvi    a,00h
  212.     outp    a
  213.     mvi    d,08h        ; load reg D for loop
  214. LOOP:    mvi    a,20h        ; bring PB5 high (no count)
  215.     outp    a
  216.     mvi    a,00h        ; bring PB5 low (advance count)
  217.     outp    a        ; 8 times only (2 thru 9)
  218.     dcr    d
  219.     jrz    STOP
  220.     jr    LOOP
  221. STOP:    lxi    b,Cia1Hrs    ; stop CIA clocks
  222.     outp    a
  223.     lxi    b,Cia2Hrs
  224.     outp    a
  225. ;
  226. ; The RTC channels are open and the CIA time-of-day clocks are stopped.
  227. ; Now we read the clock and set the CIA time.  First, the seconds ...
  228. ;
  229. CLKSET:    mvi    d,00h        ; clear D for start of read
  230.     call    RDRTC        ; read seconds (result in A, D=0 on entry,
  231.                 ; ..D=2 on return
  232.     cpi    60h        ; less than 60 seconds BCD?
  233.     jnc    NOCLK        ; (no, no clock)
  234.     lxi    b,Cia1Sec    ; set CIA seconds
  235.     outp    a
  236.     lxi    b,Cia2Sec
  237.     outp    a
  238.     sta    Secs
  239. ;
  240. ; We've set the seconds.  Now for the minutes ...
  241. ;
  242.     call    RDRTC        ; read minutes (D=2 on entry, D=4 on return)
  243.     lxi    b,Cia1Min    ; set CIA minutes
  244.     outp    a
  245.     lxi    b,Cia2Min
  246.     outp    a
  247.     sta    Mins
  248. ;
  249. ; Now for the hours.  RTC hours are in 24-hour format, but the CIA clocks
  250. ; use a 12-hour format with an am-pm flag.  We'll have to make the conversion
  251. ; remembering that we're dealing with time in Binary Coded Decimal ...
  252. ;
  253.     call    RDRTC        ; read hours and covert to 12 hour format
  254.     mov    e,a        ; store data in E
  255.     ani    3Fh        ; strip bits 6 and 7 (time is 0-23 hours)
  256.     sta    Hours
  257.     cpi    00h        ; is it 0 o'clock?
  258.     jrz    Add92        ; (yes, 12 am)
  259.     cpi    12h        ; less than 12 (am)?
  260.     jrc    NoFlag        ; (yes, no pm flag needed)
  261.     cpi    20h        ; less than 20 BCD?
  262.     jrc    Sub18        ; (yes)
  263.     cpi    22h        ; less than 22 BCD?
  264.     jrc    Sub24        ; (yes)
  265.     jr    Sub18        ; here we have 22 or 23 hours
  266. Add92:    mvi    a,92h        ; save 92 (flag goes down on CIA writes)
  267. NoFlag:    jr    Store
  268. Sub18:    sui    12h        ; subtract 18 decimal
  269.     ori    80h        ; set pm flag
  270.     jr    Store
  271. Sub24:    sui    18h        ; subtract 24 decimal
  272.     ori    80h        ; set pm flag
  273. Store:    lxi    b,Cia1Hrs    ; set CIA hours and am-pm flag
  274.     outp    a
  275.     lxi    b,Cia2Hrs
  276.     outp    a
  277. ;
  278. ; The clocks are set.  Now we get the date information and store it.
  279. ; We'll deal with it after we've finished with the clock and re-enabled
  280. ; interrupts.  (We're trying to move fast here.)
  281. ;
  282.     call    WRADDR        ; read day of week from RTC
  283.     call    RDDATA        ; ..and discard it (CP/M doesn't use it)
  284.     inr    d        ; D=7
  285. ;
  286.     call    RDRTC        ; read date (D=7 on entry; D=9 on return)
  287.     sta    Date        ; ..and store it
  288.     cpi    00h        ; is date 0?
  289.     jz    NOBAT        ; (yes, there's a problem)
  290. ;
  291.     call    RDRTC        ; read month (D=9 on entry; D=11 on return)
  292.     sta    Month        ; ..and store it
  293. ;
  294.     call    RDRTC        ; read year (D=11 on entry; D=13 on return)
  295.     sta    Year        ; ..and store it
  296. ;
  297.     mvi    d,00h        ; clear D so we can check for RTC ripple
  298.     call    RDRTC
  299.     mov    e,a        ; move RTC seconds to E
  300.     lxi    b,Cia2Sec    ; read CIA #2 seconds
  301.     cmp    e        ; are they the same
  302.     jrz    DATSET        ; (yes)
  303.     jmp    CLKSET        ; if they're different read and set again
  304. ;
  305. ; We've set the CIA clocks, which the BIOS uses to update the CP/M time
  306. ; in the System Control Block.  We've also read the date from The Right
  307. ; Time clock and stored it.  Now we have to convert it to DRI CP/M format
  308. ; and let CP/M know what it is.
  309. ;
  310. DATSET:    call    CLSCLK        ; close down the clock channels
  311.     ei            ; enable interrupts
  312. ;
  313.     lda    Month        ; convert month to binary
  314.     call    BCDBIN
  315.     sta    BMonth
  316.     lda    Date        ; convert day to binary
  317.     call    BCDBIN
  318.     sta    BDate
  319.     lda    Year        ; convert year in to binary
  320.     call    BCDBIN
  321.     sta    BYear
  322.     cpi    04Eh        ; is year less that 1978?
  323.     jc    NOTDRI        ; (yes, invalid date)
  324.     call    UNDATE        ; put the date in DRI format
  325. ;
  326. ; Now everything's ready to set the date in the System Control Block.
  327. ; BDOS Function 104 is for setting the date and time, but we won't be
  328. ; using it.  You can't set the date with Function 104 without setting
  329. ; the time, but we've already set the time more accurately (Function 104
  330. ; won't accept seconds in the time specification).  Instead, we'll use
  331. ; BDOS Function 49, Get/Set System Control Block, and write the date
  332. ; directly into the SCB.
  333. ;
  334.     shld    ScbVal        ; the date in DRI format is in HL
  335.     lxi    d,ScbPB        ; ..put it in the SCB parameter block
  336.     mvi    c,SetSCB    ; ..and call the BDOS
  337.     call    Bdos
  338. ;
  339. ; We're done now, but before we leave we'll report the date and time we
  340. ; just set.  We've saved the BCD from the RTC so we'll convert it to
  341. ; hexadecimal ASCII and print in at the console.
  342. ;
  343.     lda    Month        ; get month
  344.     call    BINHEX        ; ..convert it
  345.     shld    AMonth        ; ..and store it in string
  346.     lda    Date        ; get date
  347.     call    BINHEX
  348.     shld    ADay
  349.     lda    Year        ; get year
  350.     call    BINHEX
  351.     shld    AYear
  352. ;
  353.     lxi    d,MsgDat    ; print date
  354.     mvi    c,PrtStr
  355.     call    Bdos
  356. ;
  357.     lda    Hours        ; get hours
  358.     call    BINHEX
  359.     shld    AHours
  360.     lda    Mins        ; get minutes
  361.     call    BINHEX
  362.     shld    AMins
  363.     lda    Secs        ; get seconds
  364.     call    BINHEX
  365.     shld    ASecs
  366. ;
  367.     lxi    d,MsgTim    ; print time
  368.     mvi    c,PrtStr
  369.     call    Bdos
  370. ;
  371.     jmp    WBoot        ; salute! and happy days!
  372. ;
  373. ; We come here if the year was earlier than 1978
  374. ;
  375. NOTDRI:    lxi    d,MsgDRI    ; tell 'em it's wrong
  376.     mvi    c,PrtStr
  377.     call    Bdos
  378.     jmp    WBoot        ; ..and exit
  379. ;
  380. ; We come here if the clock is not installed in the User Port
  381. ;
  382. NOCLK:    call    CLSCLK        ; close the clock so we don't crash
  383.     ei            ; enable interrupts
  384.     lxi    d,MsgNCk
  385.     mvi    c,PrtStr    ; say the obvious
  386.     call    Bdos
  387.     jmp    WBoot        ; ..and exit
  388. ;
  389. ; We come here if the clock is not set, or if the battery is dead
  390. ;
  391. NOBAT:    call    CLSCLK        ; system crashes if we leave it open
  392.     ei            ; enable interrupts
  393.     lxi    d,MsgBat
  394.     mvi    c,PrtStr    ; give 'em the bad news
  395.     call    Bdos
  396.     jmp    WBoot        ; ..and exit
  397. ;
  398. ; Subroutine: RDRTC -- read The Right Time clock
  399. ;
  400. RDRTC:    lxi    h,LoNib
  401.     call    WRADDR
  402.     call    RDDATA
  403.     mov    m,a        ; store low nibble
  404.     inr    d        ; increment D
  405.     call    WRADDR
  406.     call    RDDATA        ; reading high nibble
  407.     ral            ; shift 4 bits left
  408.     ral
  409.     ral
  410.     ral
  411.     ora    m        ; add tens and ones
  412.     inr    d
  413.     ret
  414. ;
  415. ; Subroutine: WRADDR -- write read address to The Right Time clock
  416. ;
  417. WRADDR:    mvi    a,0FFh
  418.     lxi    b,Cia2DB    ; set CIA #2 port B to output
  419.     outp    a
  420.     mov    a,d        ; move D to A
  421.     adi    10h        ; add address write to data address
  422.     lxi    b,Cia2PB    ; send to port B
  423.     outp    a
  424.     nop            ; delay .5 microsecond minimum
  425.     nop
  426.     mov    a,d        ; move data address to A
  427.     outp    a        ; ..and send to port B
  428.     mvi    a,00h        ; clear data lines
  429.     outp    a
  430.     ret
  431. ;
  432. ; Subroutine: RDDATA -- read data from The Right Time clock
  433. ;
  434. RDDATA:    lxi    b,Cia2DB    ; set CIA #2 DDR for port B
  435.     inp    a        ; msn=output; lsn=input
  436.     ani    0F0h
  437.     outp    a
  438.     mvi    a,00h        ; clear lines
  439.     lxi    b,Cia2PB
  440.     outp    a
  441.     mvi    a,40h        ; open read line
  442.     outp    a
  443.     nop            ; delay 6 microseconds minimum
  444.     nop
  445.     nop
  446.     nop
  447.     nop
  448.     nop
  449.     nop
  450.     nop
  451.     inp    a        ; get data + 64
  452.     mov    e,a        ; ..and move it to E
  453.     mvi    a,00h        ; close read line
  454.     outp    a
  455.     nop            ; delay 1 microsecond minimum
  456.     nop
  457.     mov    a,e        ; get data back in A
  458.     ani    0Fh        ; mask off non-data
  459.     ret
  460. ;
  461. ; Subroutine: CLSCLK -- close The Right Time clock
  462. ;
  463. CLSCLK:    mvi    a,00h        ; clear for write to 1/10 second register
  464.     lxi    b,Cia1Ten
  465.     outp    a        ; this restarts CIA clocks
  466.     lxi    b,Cia2Ten
  467.     outp    a
  468.     lxi    b,Cia2PA    ; set PA2 high (close RTC enable)
  469.     inp    a
  470.     ori    04h        ; only that bit is changed
  471.     outp    a
  472. ;
  473.     lxi    b,Cia2PA    ; restore CIA#2 port setup (4 bytes)
  474.     lxi    d,CiaSav
  475.     ldax    d
  476.     outp    a        ; (1)
  477.     lxi    b,Cia2PB
  478.     inx    d
  479.     ldax    d
  480.     outp    a        ; (2)
  481.     lxi    b,Cia2DA
  482.     inx    d
  483.     ldax    d
  484.     outp    a        ; (3)
  485.     lxi    b,Cia2DB
  486.     inx    d
  487.     ldax    d
  488.     outp    a        ; (4)
  489.     ret
  490. ;
  491. ; Subroutine: BCDBIN -- converts BDC number in A to binary number in A
  492. ;
  493. BCDBIN:    mov    b,a        ; save original value in B
  494.     ani    0F0h        ; mask high nibble
  495.     rrc            ; shift right
  496.     mov    c,a        ; C = high nibble * 8
  497.     rrc            ; shift right twice more
  498.     rrc            ; A = high nibble * 2
  499.     add    c
  500.     mov    c,a        ; C = high nibble * (8 + 2)
  501.     mov    a,b        ; get original value back
  502.     ani    0Fh        ; make high nibble
  503.     add    c        ; add to binary high nibble
  504.     ret
  505. ;
  506. ; Subroutine: BINHEX -- converts binary number to hexadecimal ASCII (or
  507. ; Binary Coded Decimal to ASCII decimal).  Binary byte in A, two hexadecimal
  508. ; characters in HL (MSB in L, so we can SHLD it into a string).
  509. ;
  510. BINHEX:    mov    b,a        ; save original binary
  511.     ani    0F0h        ; get high nibble
  512.     rrc            ; move high nibble to low nibble
  513.     rrc
  514.     rrc
  515.     rrc
  516.     call    NASCII        ; convert high nibble to ASCII
  517.     mov    l,a        ; return high nibble to H
  518.     mov    a,b
  519.     ani    0Fh        ; get low nibble
  520.     call    NASCII        ; convert low nibble to ASCII
  521.     mov    h,a        ; return low nibble in L
  522.     ret
  523. ;
  524. ; Subroutine: NASCII -- (used by BINHEX) converts a hexadecimal digit to
  525. ; ASCII.  Binary data in A (lower nibble), returns ASCII character in A.
  526. ; Uses only A and F.
  527. ;
  528. NASCII:    cpi    10
  529.     jrc    Nas1        ; jump if high nibble < 10
  530.     adi    7        ; or add 7 so after adding '0' the
  531.                 ; ..character with be 'A'..'F'
  532. Nas1:    adi    '0'        ; add ASCII 0 to make a character
  533.     ret
  534. ;
  535. ; Subroutine: UNDATE -- converts a binary date to DRI format, a 16-bit
  536. ; binary integer for the number of days since January 1, 1978.
  537. ;
  538. UNDATE:    lda    BYear        ; get the binary date
  539.     mvi    b,78        ; set up a years counter
  540.     mov    c,a        ; year into C
  541.     ani    0FCh        ; is it a leap year?
  542.     cmp    c
  543.     mvi    a,28        ; assume it's not
  544.     jrnz    ItsNot
  545.     inr    a
  546. ItsNot:    sta    Feb
  547.     lxi    h,0        ; set a day counter
  548. YLoop:    mov    a,c        ; get the year
  549.     cmp    b        ; is it 78 yet?
  550.     jrz    YDone        ; (yes, we're through here)
  551.     lxi    d,365        ; set number of days in a year
  552.     dcr    c        ; decrement the year
  553.     dcr    a        ; ..both times
  554.     ani    0FCh        ; ..and check for a leap year
  555.     cmp    c
  556.     jrnz    NoLeap        ; (no leap)
  557.     inx    d        ; make days 366
  558. NoLeap:    dad    d        ; now sum the days up
  559.     jr    YLoop
  560. ;
  561. ; Years are done, now for the months
  562. ;
  563. YDone:    shld    Days        ; save days so far
  564.     lda    BMonth        ; get the binary month
  565.     lxi    b,Jan        ; point to the months table
  566.     mvi    h,0
  567.     mov    l,a
  568.     dad    b        ; set the months table pointer
  569.     mov    b,h
  570.     mov    c,l
  571.     dcx    b
  572.     lhld    Days
  573.     mvi    d,0        ; get ready to add
  574. Mloop:    dcr    a        ; decrement the year
  575.     dcx    b
  576.     jrz    MDone        ; (we're done with months)
  577.     push    psw
  578.     ldax    b        ; get days
  579.     mov    e,a
  580.     dad    d        ; ..and add to total
  581.     pop    psw
  582.     jr    Mloop
  583. ;
  584. ; Months are done, now finally the days
  585. ;
  586. Mdone:    lda    BDate        ; get the days in binary
  587.     mov    e,a        ; get ready to add (this is easy)
  588.     mvi    d,0
  589.     dad    d        ; ..add them to total
  590.     ret            ; ..and we're done (total in HL)
  591. ;
  592.     end
  593. ;
  594.